package com.shop.resource.remote.server;

import com.shop.resource.bean.model.EsOutputModel;
import com.shop.resource.bean.model.EsQueryModel;
import com.shop.resource.remote.IEsRemoteInterface;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.action.search.ClearScrollRequest;
import org.elasticsearch.action.search.ClearScrollResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchScrollRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.Scroll;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.junit.Assert;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.List;

/**
 * @Description:
 * @author zhoulk
 * @date: 2019/12/2
 */
public class EsRemoteService implements IEsRemoteInterface {

    @Autowired
    private RestHighLevelClient highLevelClient;

    public <T> EsOutputModel<T> multiMatchQuery(EsQueryModel queryModel, Class<T> clazz) {
        String scrollId = queryModel.getScrollId();
        EsOutputModel<T> esOutputModel = new EsOutputModel<>();
        if (StringUtils.isNotBlank(scrollId)) {
            try {
                SearchHit[] searchHits = scroll(scrollId);

            } catch (IOException e) {
                return esOutputModel;
            }
        }
        final Scroll scroll = new Scroll(TimeValue.timeValueMinutes(10L));
        SearchRequest searchRequest = new SearchRequest("article");
        searchRequest.scroll(scroll);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder filters = new BoolQueryBuilder();
        searchSourceBuilder.postFilter(filters);//添加filter
        searchSourceBuilder.size(queryModel.getSize());
        searchRequest.source(searchSourceBuilder);

        String[] queryFields = queryModel.getQueryFields();
        String queryValue = queryModel.getQueryValue();
        if (queryFields != null && queryFields.length >0 && StringUtils.isNotBlank(queryValue)) {
            QueryBuilder multiMatchQuery = new MultiMatchQueryBuilder(queryValue, queryFields);
            searchSourceBuilder.query(multiMatchQuery);//添加搜索内容
        }

        Object filter = queryModel.getFilters();
        if (filter != null) {
            Class filterClazz = filter.getClass();
            Field[] fields = filterClazz.getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                try {
                    Object value = field.get(filter);
                    String fieldName = field.getName();
                    filters.must(QueryBuilders.matchQuery(fieldName, value));
                } catch (IllegalAccessException e) {
                    continue;
                }
            }
        }

        try {
            SearchResponse searchResponse = highLevelClient.search(searchRequest, RequestOptions.DEFAULT); //通过发送初始搜索请求来初始化搜索上下文
            scrollId = searchResponse.getScrollId();
            SearchHit[] searchHits = searchResponse.getHits().getHits();

            while (searchHits != null && searchHits.length > 0) { //通过循环调用搜索滚动api来检索所有搜索命中，直到没有文档返回
                //处理返回的搜索结果
                SearchScrollRequest scrollRequest = new SearchScrollRequest(scrollId); //创建一个新的搜索滚动请求，保存最后返回的滚动标识符和滚动间隔
                scrollRequest.scroll(scroll);
                searchResponse = highLevelClient.scroll(scrollRequest, RequestOptions.DEFAULT);
                scrollId = searchResponse.getScrollId();
                searchHits = scroll (scrollId);
            }

        } catch (Exception ignored) {

        } finally {
            if (StringUtils.isNotBlank(scrollId)) {
                boolean succeeded = false;
                do {
                    ClearScrollRequest clearScrollRequest = new ClearScrollRequest(); //完成滚动后，清除滚动上下文
                    clearScrollRequest.addScrollId(scrollId);
                    ClearScrollResponse clearScrollResponse = null;
                    try {
                        clearScrollResponse = highLevelClient.clearScroll(clearScrollRequest, RequestOptions.DEFAULT);
                        succeeded = clearScrollResponse.isSucceeded();
                    } catch (IOException e) {
                    }
                } while (!succeeded);
            }
        }
        return null;
    }

    private SearchHit [] scroll(String scrollId) throws IOException {
        final Scroll scroll = new Scroll(TimeValue.timeValueMinutes(10L));
        SearchScrollRequest scrollRequest = new SearchScrollRequest(scrollId); //创建一个新的搜索滚动请求，保存最后返回的滚动标识符和滚动间隔
        scrollRequest.scroll(scroll);
        SearchResponse searchResponse  = highLevelClient.scroll(scrollRequest, RequestOptions.DEFAULT);
        scrollId = searchResponse.getScrollId();
        SearchHit [] searchHits = searchResponse.getHits().getHits();
        return searchHits;
    }
}
